﻿/*
   Copyright 2012 University of Southampton

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

using System;
using System.Linq;
using System.Security.Principal;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using uk.ac.soton.ses.DAL;
using System.Collections.Generic;
using System.IO;
using Microsoft.SharePoint;

namespace uk.ac.soton.ses.UserControls
{
    public partial class ExperimentDataItems : UserControl
    {
        private int _experimentID = -1;
        private bool _initialised = false;
        MaterialsMetadataContext _dbcontext = null;
        HDCPlugins<IHDCExperimentDataFilePlugin> _plugins = null;

        public EventHandler FullRebindRequired;

        /// <summary>
        /// A private class for populating the data for the gridview
        /// </summary>
        private class View_Users_DataItem
        {
            public Int32 ACEID { get; set; }
            public Int32 DBUserID { get; set; }
            public string Username { get; set; }
            public string Name { get; set; }
            public string Email { get; set; }
            public bool WriteAccessGranted { get; set; }
        }

        #region Page life cycle methods

        /// <summary>
        /// OnInit in ASP.NET page life cycle overridden. We configure events here.
        /// </summary>
        /// <param name="e">Event arguments received by events</param>
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            if (int.TryParse(Page.Request.QueryString["ID"], out this._experimentID) && this._experimentID > 0)
            {
                //Load the database context
                this._dbcontext = HttpContext.Current.GetMaterialsDBContext();

                //Data Items view
                this.View_ExperimentDataItems.RowEditing += new GridViewEditEventHandler(view_ExperimentDataItems_RowEditing);
                this.View_ExperimentDataItems.RowCancelingEdit += new GridViewCancelEditEventHandler(view_ExperimentDataItems_RowCancelingEdit);
                this.View_ExperimentDataItems.RowUpdating += new GridViewUpdateEventHandler(view_ExperimentDataItems_RowUpdating);
                this.View_ExperimentDataItems.RowDataBound += new GridViewRowEventHandler(view_ExperimentDataItems_RowDataBound);

                //File upload events
                this.btn_UploadFile.Click += new EventHandler(btn_UploadFile_Click);

                //Load plugins
                this._plugins = new HDCPlugins<IHDCExperimentDataFilePlugin>();

                this.cb_ShowDeleted.CheckedChanged += new EventHandler(cb_ShowDeleted_CheckedChanged);

                //The data binding can continue in Page_Load
                this._initialised = true;
            }
        }

        private void cb_ShowDeleted_CheckedChanged(object sender, EventArgs e)
        {
            this.DataBindExperimentDataItems();
        }

        /// <summary>
        /// Page_Load in ASP.NET page life cycle. We databind controls here.
        /// </summary>
        /// <param name="sender">Usual sender object received by events</param>
        /// <param name="e">Event arguments received by events</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack && this._initialised)
            {
                this.DataBindAllControls();
            }
        }

        #endregion

        #region Data binding methods

        /// <summary>
        /// Parent data bind method that calls data binding on all required controls
        /// </summary>
        private void DataBindAllControls()
        {
            //Bind the user access grid view
            this.DataBindExperimentDataItems();
        }

        /// <summary>
        /// Data binding data items view
        /// </summary>
        private void DataBindExperimentDataItems()
        {
            this.View_ExperimentDataItems.DataSource = this._dbcontext.GetExperimentDataFilesByExperimentID(this._experimentID, this.cb_ShowDeleted.Checked);
            this.View_ExperimentDataItems.DataBind();
        }

        #endregion

        #region ExperimentDataItems Events

        private void view_ExperimentDataItems_RowUpdating(object sender, GridViewUpdateEventArgs e)
        {
            int selectedID = (int)this.View_ExperimentDataItems.DataKeys[this.View_ExperimentDataItems.EditIndex]["ID"];
            string selectedFileName = (string)this.View_ExperimentDataItems.DataKeys[this.View_ExperimentDataItems.EditIndex]["Filename"];

            //If the experiment data file was null, it's probably been deleted by someone else so do nothing as we're rebinding anyway
            //Extract the new values
            for (int i = 0; i < this.View_ExperimentDataItems.Columns.Count; i++)
            {
                TableCell cellData = this.View_ExperimentDataItems.Rows[e.RowIndex].Cells[i];
                this.View_ExperimentDataItems.Columns[i].ExtractValuesFromCell(e.NewValues, (DataControlFieldCell)cellData, DataControlRowState.Edit, false);
            }

            //Look up the description
            object newDescriptionObject = e.NewValues["Description"];
            string newDescription = (newDescriptionObject == null ? String.Empty : newDescriptionObject.ToString());

            //Update the database
            this._dbcontext.UpdateExperimentDataFile(selectedID, newDescription);
            this._dbcontext.SaveChanges();

            this.View_ExperimentDataItems.EditIndex = -1;
            this.DataBindExperimentDataItems();
        }

        private void view_ExperimentDataItems_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
        {
            this.View_ExperimentDataItems.EditIndex = -1;
            this.DataBindExperimentDataItems();
        }

        private void view_ExperimentDataItems_RowEditing(object sender, GridViewEditEventArgs e)
        {
            this.View_ExperimentDataItems.EditIndex = e.NewEditIndex;
            this.DataBindExperimentDataItems();
        }

        private void view_ExperimentDataItems_RowDataBound(object sender, GridViewRowEventArgs e)
        {
            GridViewRow gvr = (GridViewRow)e.Row;
            if (e.Row.RowIndex >= 0)
            {
                ExperimentDataFile boundExperimentDataFile = e.Row.DataItem as ExperimentDataFile;
                if (boundExperimentDataFile != null)
                {
                    //Set the download link if we can generate it
                    HyperLink httpDownloadControl = gvr.FindControl("lnk_DownloadHttp") as HyperLink;
                    //Label lblLocation = gvr.FindControl("lbl_Location") as Label;
                    httpDownloadControl.Text = boundExperimentDataFile.Filename;

                    if (boundExperimentDataFile.IsDeleted == true)
                    {
                        gvr.CssClass = "DeletedItem";
                    }
                    else
                    {
                        httpDownloadControl.NavigateUrl = boundExperimentDataFile.GetWebPath(this._dbcontext) ?? string.Empty;
                        httpDownloadControl.ToolTip = "Location: " + (boundExperimentDataFile.GetUNCPath(this._dbcontext) ?? boundExperimentDataFile.GetFullPath());
                    }


                    //Populate the plugin dropdown list
                    DropDownList ddl = gvr.FindControl("lst_ImportPlugins") as DropDownList;
                    ddl.Items.Clear();
                    ddl.Items.Add(new ListItem("Select a plugin to execute:"));
                    foreach (IHDCExperimentDataFilePlugin plugin in this._plugins.Plugins)
                    {
                        ddl.Items.Add(new ListItem(plugin.Name, plugin.GetType().AssemblyQualifiedName));
                    }
                    Page.ClientScript.RegisterClientScriptBlock(this.GetType(), ddl.ClientID, "$(window).load(function(){$('#" + ddl.ClientID + "')[0].selectedIndex=0;});", true);
                }
            }
        }

        /// <summary>
        /// Event handler for when the user selects from the data import plugins drop down menu
        /// </summary>
        /// <param name="sender">The control that generated the event</param>
        /// <param name="e">The event arguments</param>
        protected void ExecuteImportPlugin(object sender, EventArgs e)
        {
            DropDownList ddl = (DropDownList)sender;
            GridViewRow gvr = (GridViewRow)ddl.Parent.Parent;
            string fileIDstr = this.View_ExperimentDataItems.DataKeys[gvr.RowIndex]["ID"].ToString();
            int fileID;
            if (ddl.SelectedIndex > 0 && int.TryParse(fileIDstr, out fileID))
            {
                try
                {
                    IHDCExperimentDataFilePlugin selectedImportPlugin = this._plugins.Plugins[ddl.SelectedIndex - 1];
                    if (selectedImportPlugin.GetType().AssemblyQualifiedName == ddl.SelectedValue)
                    {
                        selectedImportPlugin.ExecutePlugin(fileID, this, this._dbcontext);
                        this.FullRebindRequired(this, new EventArgs());
                        string message = String.Format("Plug in finished");
                        Label lbl_ParameterImportError = (Label)gvr.FindControl("lbl_ParameterImportError");
                        lbl_ParameterImportError.Text = message;
                    }
                }
                catch (Exception ex)
                {
                    string errorMessage = String.Format("Plug in failed with error: {0}", ex.Message);
                    Label lbl_ParameterImportError = (Label)gvr.FindControl("lbl_ParameterImportError");
                    lbl_ParameterImportError.Text = errorMessage;
                }
            }
        }

        #endregion

        #region File upload events

        private void btn_UploadFile_Click(object sender, EventArgs e)
        {
            try
            {
                Experiment exp = this._dbcontext.GetExperimentByID(this._experimentID);
                if (this.FileUpload_NewDataItem.HasFile)
                {
                    SPSecurity.RunWithElevatedPrivileges(delegate()
                    {
                        //Save it somewhere temporarily
                        string tempFileName = Path.GetTempFileName();
                        FileUpload_NewDataItem.SaveAs(tempFileName);

                        //Add it to the experiment
                        ExperimentDataFile uploadedFile = exp.AddFile(tempFileName, FileUpload_NewDataItem.FileName, this._dbcontext);
                    });
                    //Ask for a full rebind
                    this.FullRebindRequired(this, new EventArgs());
                    this.DataBindAllControls();
                    this.lbl_Message.Text = "File uploaded successfully";
                }
            }
            catch (Exception ex)
            {
                this.lbl_Message.Text = "Error adding file:" + ex.Message;
            }
        }

        #endregion
    }
}
